package mac5789.projeto4.parser;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import mac5789.projeto4.model.DeclarableWorldModel;
import mac5789.projeto4.model.WorldModel;

/**
 * 
 * @author lundberg
 * 
 */
public class WorldModelParser {

	private InputStream input;

	private DeclarableWorldModel world;

	private Map<String, DeclarableWorldModel.TransitionModelBuilder> transitions;

	private int currentIndex;

	private List<String> lines;

	public WorldModelParser(InputStream input) {
		this.input = input;
		world = new DeclarableWorldModel();
		transitions = new HashMap<String, DeclarableWorldModel.TransitionModelBuilder>();
	}

	public WorldModel parse() {
		this.readLines();
		while (currentIndex < lines.size()) {
			if ("states".equals(currentLine())) {
				currentIndex++;
				while (!"endstates".equals(currentLine())) {
					String[] states = currentLine().split(",");
					world.withStates(states);
					world.withInitialState(states[0]);
					world.withGoal(states[states.length - 1]);
					currentIndex++;
				}
				currentIndex++;
			}
			if (currentLine().startsWith("action ")) {
				String action = currentLine().substring("action ".length());
				world.withAction(action);
				currentIndex++;
				while (!("endaction".equals(currentLine()) || "endation".equals(currentLine()))) {
					String[] triple = currentLine().split(" ");
					assert triple.length == 3;
					String on = triple[0];
					String to = triple[1];
					double probability = Double.parseDouble(triple[2]);
					storeTransition(on, action, to, probability);
					currentIndex++;
				}
				currentIndex++;
			}
			if ("reward".equals(currentLine())) {
				currentIndex++;
				while (!"endreward".equals(currentLine())) {
					String[] tuple = currentLine().split(" ");
					assert tuple.length == 2;
					String state = tuple[0];
					double reward = Double.parseDouble(tuple[1]);
					world.withReward(state, reward);
					currentIndex++;
				}
				currentIndex++;
			}
			if ("cost".equals(currentLine())) {
				currentIndex++;
				while (!"endcost".equals(currentLine())) {
					String[] tuple = currentLine().split(" ");
					assert tuple.length == 2;
					String action = tuple[0];
					double cost = Double.parseDouble(tuple[1]);
					world.withCost(action, cost);
					currentIndex++;
				}
				currentIndex++;
			}
			if (currentLine().startsWith("discount factor ")) {
				double discountFactor = Double.parseDouble(currentLine().substring("discount factor ".length()));
				world.withDiscountFactor(discountFactor);
				currentIndex++;
			}
			if (currentLine().startsWith("maxiterations ")) {
				int maxIteractions = Integer.parseInt(currentLine().substring("maxiterations ".length()));
				world.withMaxIteractions(maxIteractions);
				currentIndex++;
			}

		}
		for (String transformationKey : this.transitions.keySet()) {
			this.transitions.get(transformationKey).build();
		}
		world.withDefaultCost(0.0);
		return world;
	}

	private void storeTransition(String on, String action, String to, double probability) {
		String key = on + "," + action;
		if (!transitions.containsKey(key)) {
			transitions.put(key, world.withTransition().on(on).given(action));
		}
		transitions.get(key).to(to, probability);
	}

	private String currentLine() {
		return lines.get(currentIndex);
	}

	private void readLines() {
		BufferedReader reader = new BufferedReader(new InputStreamReader(input));
		try {
			lines = new ArrayList<String>();
			String line;
			while ((line = reader.readLine()) != null) {
				line = line.trim().replaceAll("\\s+", " ").replaceAll("\\s*,\\s*", ",").replaceAll("//.*", "");

				if (line.length() > 0) {
					lines.add(line);
				}
			}
			currentIndex = 0;
		} catch (IOException e) {
			throw new RuntimeException("Erro de I/O lendo de entrada: " + e.getMessage(), e);
		}
	}
}
